/*
	WriteBackUnit
*/
`include "define.v"
module wbu
(	
	//	exc irq
	input	wire				wbu_mei_flag_i            ,
    input	wire				wbu_msi_flag_i            ,
    input	wire				wbu_mti_flag_i            ,
    input	wire				wbu_instr_addr_misalig_i ,
    input	wire				wbu_instr_acc_fault_i    ,
    input	wire				wbu_illegal_instr_i      ,
    input	wire				wbu_ebreak_i             ,
    input	wire				wbu_load_addr_misalig_i  ,
    input	wire				wbu_load_acc_fault_i     ,
    input	wire				wbu_store_addr_misalig_i ,
    input	wire				wbu_store_acc_fault_i    ,
    input	wire				wbu_ecall_i              ,
    input	wire				wbu_mret_flag_i   , 
    input	wire				wbu_wfi_flag_i    ,
    input	wire				wbu_exc_flag_i    ,
    
	input 	wire 	[63:00]		wbu_mstatus_i,
	input 	wire 	[63:00]		wbu_mie_i,
	input 	wire 	[63:00]		wbu_mtvec_i,	
	//
	input	wire	[63:00]		wbu_alu_output_i,
	input	wire	[63:00]		wbu_lsu_output_i,
	input	wire	[63:00]		wbu_mdu_output_i,
	//	gpr
	input 	wire				wbu_gpr_write_back_en_i,
	input 	wire	[04:00]		wbu_gpr_write_back_id_i,
	input	wire				wbu_gpr_write_back_from_alu_i,
	input	wire				wbu_gpr_write_back_from_lsu_i,
	input	wire				wbu_gpr_write_back_from_mdu_i,
	//	csr
	input 	wire				wbu_csr_write_back_en_i,
	input 	wire	[11:00]		wbu_csr_write_back_id_i,
	input	wire	[63:00]		wbu_csr_write_back_data_i,
	//
	output	wire				wbu_mei_flag_o ,
    output	wire				wbu_msi_flag_o ,
    output	wire				wbu_mti_flag_o ,
    output	wire				wbu_instr_addr_misalig_o,
    output	wire				wbu_instr_acc_fault_o   ,
    output	wire				wbu_illegal_instr_o     ,
    output	wire				wbu_ebreak_o            ,
    output	wire				wbu_load_addr_misalig_o ,
    output	wire				wbu_load_acc_fault_o    ,
    output	wire				wbu_store_addr_misalig_o,
    output	wire				wbu_store_acc_fault_o   ,
    output	wire				wbu_ecall_o             ,
    output	wire				wbu_mret_flag_o   , 
    output	wire				wbu_wfi_flag_o    ,
    output	wire				wbu_exc_flag_o    ,
    output	wire				wbu_irq_flag_o    ,
    output	wire				wbu_exc_irq_flag_o,
	output	wire	[63:00]		wbu_exc_irq_srv_prog_addr_o,
	//	
	output	wire				wbu_gpr_write_back_en_o,
	output	wire	[04:00]		wbu_gpr_write_back_id_o,
	output	wire				wbu_csr_write_back_en_o,
	output	wire	[11:00]		wbu_csr_write_back_id_o,
	//	write back data
	output	wire	[63:00]		wbu_gpr_write_back_data_o,
	output	wire	[63:00]		wbu_csr_write_back_data_o
);
	//
	wire    [63:00]     mie     			=   wbu_mie_i;
    wire    [63:00]     mstatus 			=   wbu_mstatus_i;
	wire 	[63:00]		exc_irq_srv_prog_offset;
	// 
    assign		wbu_instr_addr_misalig_o	=	wbu_instr_addr_misalig_i;
    assign		wbu_instr_acc_fault_o   	=	wbu_instr_acc_fault_i   ;
    assign		wbu_illegal_instr_o     	=	wbu_illegal_instr_i     ;
    assign		wbu_ebreak_o            	=	wbu_ebreak_i            ;
    assign		wbu_load_addr_misalig_o 	=	wbu_load_addr_misalig_i ;
    assign		wbu_load_acc_fault_o    	=	wbu_load_acc_fault_i    ;
    assign		wbu_store_addr_misalig_o	=	wbu_store_addr_misalig_i;
    assign		wbu_store_acc_fault_o   	=	wbu_store_acc_fault_i   ;
    assign		wbu_ecall_o             	=	wbu_ecall_i             ;
    assign		wbu_mret_flag_o   			=	wbu_mret_flag_i   ; 
    assign		wbu_wfi_flag_o    			=	wbu_wfi_flag_i    ;
    assign		wbu_exc_flag_o    			=	wbu_exc_flag_i    ;

	assign  wbu_mei_flag_o                  =   !wbu_exc_flag_i   && `MEIE   &&   wbu_mei_flag_i    &&  `MIE;
    assign  wbu_msi_flag_o                  =   !wbu_exc_flag_i   && `MSIE   &&  !wbu_msi_flag_i    &&  `MIE;
    assign  wbu_mti_flag_o                  =   !wbu_exc_flag_i   && `MTIE   &&  !wbu_mti_flag_i    &&  `MIE;
    //  如果有异常发生则屏蔽中断
    assign  wbu_irq_flag_o                  =   (    wbu_mei_flag_o               || wbu_msi_flag_o        || wbu_mti_flag_o      );
    assign	wbu_exc_irq_flag_o				=	wbu_exc_flag_i || wbu_irq_flag_o;
	//
	assign  	exc_irq_srv_prog_offset[63:06]      =   58'b0;
    assign  	exc_irq_srv_prog_offset[05]         =   wbu_mtvec_i[00]  && wbu_mei_flag_i; 
    assign  	exc_irq_srv_prog_offset[04]         =   wbu_mtvec_i[00]  && wbu_mti_flag_i;               
    assign  	exc_irq_srv_prog_offset[03:02]      =   {2{wbu_mtvec_i[00] && wbu_irq_flag_o}};
    assign  	exc_irq_srv_prog_offset[01:00]      =   2'b0; 
	assign		wbu_exc_irq_srv_prog_addr_o			=	{wbu_mtvec_i[63:02],2'b00} + exc_irq_srv_prog_offset;
	//	写回使能
	assign	wbu_gpr_write_back_en_o			=	wbu_gpr_write_back_en_i && !wbu_exc_irq_flag_o;
	assign	wbu_csr_write_back_en_o			=	wbu_csr_write_back_en_i && !wbu_exc_irq_flag_o;
	//	写回ID
	assign	wbu_gpr_write_back_id_o			=	wbu_gpr_write_back_id_i;
	assign	wbu_csr_write_back_id_o			=	wbu_csr_write_back_id_i;

	//	写回数据
	assign	wbu_gpr_write_back_data_o 		=   ( {64{wbu_gpr_write_back_from_alu_i}} &  wbu_alu_output_i )|	
                                    			( {64{wbu_gpr_write_back_from_lsu_i}} &  wbu_lsu_output_i )|
												( {64{wbu_gpr_write_back_from_mdu_i}} &  wbu_mdu_output_i );

	assign	wbu_csr_write_back_data_o		=	wbu_csr_write_back_data_i;
	
endmodule

